#include <cstddef>
#include <cstring>
#include <string.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>

using namespace std;

class CowString{
public:
    CowString()
        :_pstr(new char[5]()+4){
            counterInit();
        }

    ~CowString(){
        counterInc();
        if(counterNum()==0) delete[] (_pstr-4);
    }
    
    CowString(const char *pstr)
        :_pstr(new char[strlen(pstr)+5]+4){
            counterInit();
            strcpy(_pstr,pstr);
        }

    CowString & operator=(const CowString & rhs)
    {

        counterInc();
        if(counterNum()==0){
            delete [] (_pstr-4);
        }
        _pstr=new char[strlen(rhs._pstr)+5]()+4;
       strcpy(_pstr,rhs._pstr);
       counterDec();
       return *this;
    }


    friend class CharPoxy;
    


    size_t mysize(){
        return strlen(_pstr);
    }

    size_t counterNum(){
        return *(int *)(_pstr-4);
    }

    void counterDec(){
        ++*(int *)(_pstr-4);
    }

    void counterInc(){
        --*(int *)(_pstr-4);
    }

    void counterInit(){
        *(int *)(_pstr-4)=1;
    }
    

private:

    class CharPoxy{
    public:
        CharPoxy( CowString &s,size_t index)
        :_s(s)
         ,_index(index)
        {
    
        }

        char operator=(const char &c){
            if(_index>=_s.mysize()){
                static char nullchar='\0';
                cerr<<"--- Index Error ---"<<endl;
                return nullchar;
            }

            if(_s.counterNum()>1){
                _s.counterInc();
                char *temp=new char[_s.mysize()+5]()+4;
                strcpy(temp,_s._pstr);
                _s._pstr=temp;
                *(int *)(_s._pstr-4)=1;
            }
                _s._pstr[_index]=c;
                return _s._pstr[_index];
        }


    friend ostream & operator<<(ostream &os,const CharPoxy &rhs);





    private:
        CowString & _s;
        size_t _index;

    };

public:
    
    CharPoxy  operator[](size_t index){
        return CharPoxy(*this,index);
    }
    friend ostream & operator<<(ostream &os,const CowString &rhs);
    friend ostream & operator<<(ostream &os,const CharPoxy &rhs);

    char *_pstr;

};
ostream & operator<<(ostream &os,const CowString &rhs){
    os<<rhs._pstr;
    return os;
}
ostream & operator<<(ostream &os,const CowString::CharPoxy &rhs){
    if(rhs._index>rhs._s.mysize()){
        os<<" Index Error ";
        return os;
    }
    os<<rhs._s._pstr[rhs._index];
    return os;
}


void test(){
    CowString s1="hello";
    cout<<"--- s1: "<<s1<<" ---"<<endl;
    cout<<"--- s1[2]: "<<s1[2]<<" ---"<<endl;
    s1[0]='H';
    cout<<"--- s1: "<<s1<<" ---"<<endl;
    cout<<"--- s1[10]: "<<s1[10]<<" ---"<<endl;
}

int main()
{
 test();
 return 0;
}

